#include <stdio.h>
#include <stdlib.h>
#include <omp.h>

void socket_work(int socket_num, int n_thrds);

int main(void)
{
    int n_sockets, socket_num, n_thrds_on_socket;

    omp_set_nested(1); // or env var= OMP_NESTED=true
    omp_set_max_active_levels(2); // or env var= OMP_MAX_ACTIVE_LEVELS=2

    n_sockets = omp_get_num_places();
    n_thrds_on_socket = omp_get_place_num_procs(0);

    // OMP_NUM_THREADS=2,4
    // OMP_PLACES="{0,2,4,6},{1,3,5,7}" #2 sockets; even/odd proc-ids
    // OMP_AFFINITY_FORMAT=\
    // "nest_level= %L, parent_thrd_num= %a, thrd_num= %n, thrd_affinity= %A"

    #pragma omp parallel num_threads(n_sockets) private(socket_num)
    {
        socket_num = omp_get_place_num();

        if(socket_num == 0)
            printf(" LEVEL 1 AFFINITIES 1 thread/socket, %d sockets:\n\n", n_sockets);

        // not needed if OMP_DISPLAY_AFFINITY=TRUE
        omp_display_affinity(NULL);

        // OUTPUT:
        // LEVEL 1 AFFINITIES 1 thread/socket, 2 sockets:
        // nest_level= 1, parent_thrd_num= 0, thrd_num= 0, thrd_affinity= 0,2,4,6
        // nest_level= 1, parent_thrd_num= 0, thrd_num= 1, thrd_affinity= 1,3,5,7

        socket_work(socket_num, n_thrds_on_socket);
    }

    return 0;
}

void socket_work(int socket_num, int n_thrds)
{
    #pragma omp parallel num_threads(n_thrds)
    {
        if(omp_get_thread_num() == 0)
            printf(" LEVEL 2 AFFINITIES, %d threads on socket %d\n", n_thrds, socket_num);

        // not needed if OMP_DISPLAY_AFFINITY=TRUE
        omp_display_affinity(NULL);

        // OUTPUT:
        // LEVEL 2 AFFINITIES, 4 threads on socket 0
        // nest_level= 2, parent_thrd_num= 0, thrd_num= 0, thrd_affinity= 0
        // nest_level= 2, parent_thrd_num= 0, thrd_num= 1, thrd_affinity= 2
        // nest_level= 2, parent_thrd_num= 0, thrd_num= 2, thrd_affinity= 4
        // nest_level= 2, parent_thrd_num= 0, thrd_num= 3, thrd_affinity= 6
        // LEVEL 2 AFFINITIES, 4 threads on socket 1
        // nest_level= 2, parent_thrd_num= 1, thrd_num= 0, thrd_affinity= 1
        // nest_level= 2, parent_thrd_num= 1, thrd_num= 1, thrd_affinity= 3
        // nest_level= 2, parent_thrd_num= 1, thrd_num= 2, thrd_affinity= 5
        // nest_level= 2, parent_thrd_num= 1, thrd_num= 3, thrd_affinity= 7

        // ... Do Some work on Socket
    }
}
